---@class components
---@field mod_pono_drowning component_mod_pono_drowning

---@class component_mod_pono_drowning
---@field inst ent
---@field health_penalty number 溺水生命值惩罚
---@field hunger_penalty number 溺水饥饿值惩罚
---@field sanity_penalty number 溺水理智值惩罚
---@field min_value number 三维最低保留值
---@field moisture_gain number 潮湿度增加
---@field item_drop_fraction number 物品掉落比例
local mod_pono_drowning = Class(

---@param self component_mod_pono_drowning
---@param inst ent
function(self, inst)
    self.inst = inst
    
    -- 默认溺水惩罚参数（符合官方wiki描述）
    self.health_penalty = 25
    self.hunger_penalty = 25
    self.sanity_penalty = 25
    self.min_value = 30  -- 三维不会低于此值
    self.moisture_gain = 100
    self.item_drop_fraction = 0.2  -- 1/5
end,
nil,
{})

-- 设置生命值惩罚
function mod_pono_drowning:SetHealthPenalty(value)
    self.health_penalty = value
end

-- 设置饥饿值惩罚
function mod_pono_drowning:SetHungerPenalty(value)
    self.hunger_penalty = value
end

-- 设置理智值惩罚
function mod_pono_drowning:SetSanityPenalty(value)
    self.sanity_penalty = value
end

-- 设置最低保留值
function mod_pono_drowning:SetMinValue(value)
    self.min_value = value
end

-- 设置潮湿度增加
function mod_pono_drowning:SetMoistureGain(value)
    self.moisture_gain = value
end

-- 设置物品掉落比例
function mod_pono_drowning:SetItemDropFraction(value)
    self.item_drop_fraction = value
end

-- 触发溺水事件
---@param data table|nil 包含 entry_x, entry_y, entry_z 的表（跃入位置）
function mod_pono_drowning:TriggerDrown(data)
    local inst = self.inst
    
    -- 获取跃入位置，如果没有提供则使用当前位置
    local spawn_x, spawn_y, spawn_z
    if data and data.entry_x and data.entry_y and data.entry_z then
        spawn_x = data.entry_x
        spawn_y = data.entry_y
        spawn_z = data.entry_z
    else
        spawn_x, spawn_y, spawn_z = inst.Transform:GetWorldPosition()
    end
    
    -- 应用三维惩罚（不会低于min_value）
    if inst.components.health then
        local current_health = inst.components.health.currenthealth
        local new_health = math.max(self.min_value, current_health - self.health_penalty)
        inst.components.health:SetCurrentHealth(new_health)
    end
    
    if inst.components.hunger then
        local current_hunger = inst.components.hunger.current
        local new_hunger = math.max(self.min_value, current_hunger - self.hunger_penalty)
        -- 使用DoDelta来改变饥饿值
        local delta = new_hunger - current_hunger
        inst.components.hunger:DoDelta(delta, false)
    end
    
    if inst.components.sanity then
        local current_sanity = inst.components.sanity.current
        local new_sanity = math.max(self.min_value, current_sanity - self.sanity_penalty)
        -- 使用DoDelta来改变理智值
        local delta = new_sanity - current_sanity
        inst.components.sanity:DoDelta(delta, false)
    end
    
    -- 增加潮湿度
    if inst.components.moisture then
        inst.components.moisture:DoDelta(self.moisture_gain)
    end
    
    -- 扣除能量值（根据池塘类型调整，且不低于30）
    if inst.components.mod_pono_energy then
        local current_energy = inst.components.mod_pono_energy:GetVal()
        local energy_penalty = 15  -- 默认扣除15点
        
        -- 如果是湖泊溺水，只扣除7点
        if data and data.pond_type == "oasislake" then
            energy_penalty = 7
        end
        
        -- 计算扣除后的能量值
        local new_energy = current_energy - energy_penalty
        
        -- 如果扣除后低于30，则设置为30
        -- 如果当前能量就低于30，则恢复到30
        if new_energy < 30 or current_energy < 30 then
            new_energy = 33
        end
        
        -- 应用能量变化
        local delta = new_energy - current_energy
        inst.components.mod_pono_energy:DoDelta(delta)
    end
    
    -- 如果处于加速状态，取消加速
    if inst:HasTag("pono_speed_mode") then
        inst:RemoveTag("pono_speed_mode")
        
        -- 触发能量值变化事件以更新状态
        if inst.components.mod_pono_energy then
            inst:PushEvent("mod_pono_energy_val_change", {val = inst.components.mod_pono_energy:GetVal()})
        end
    end

    inst:AddTag("busy")
    inst:AddTag("pono_drowning_busy")
    inst:AddTag("notarget")  -- 防止被攻击
    inst:AddTag("noattack")  -- 防止攻击
    
    -- 服务器端禁用移动（防止传送后一瞬间能操控）
    if inst.components.locomotor then
        inst.components.locomotor:Stop()
        inst.components.locomotor:Clear()
        inst.components.locomotor:SetExternalSpeedMultiplier(inst, "drowning_server", 0)
    end
    
    -- 禁用playercontroller以阻止所有输入
    if inst.components.playercontroller then
        inst.components.playercontroller:Enable(false)
    end
    
    -- 尝试直接调用ScreenFade（如果inst就是玩家实体）
    if inst.ScreenFade then
        -- 立即黑屏
        inst:ScreenFade(false, 0)
        
        -- 2.5秒后渐变恢复
        inst:DoTaskInTime(2.5, function()
            if inst:IsValid() and inst.ScreenFade then
                inst:ScreenFade(true, 1)
            end
        end)
    end
    
    -- 2. 触发客户端禁用控制和黑屏事件
    inst:PushEvent("pono_drowning_start")
    
    --[[ 原ScreenFade方式（已注释，改用事件）
    if inst.ScreenFade then
        inst:ScreenFade(true, 0)
        
        inst:DoTaskInTime(3.0, function()
            if inst:IsValid() and inst.ScreenFade then
                inst:ScreenFade(false, 1)
            end
        end)
    end
    --]]
    
    --[[ RPC方式（已注释）
    if inst.userid then
        SendModRPCToClient(GetClientModRPC("mod_pono", "drowning_screenfade"), inst.userid, 3)
    end
    --]]
    
    -- 3. 在1秒后传送
    inst:DoTaskInTime(1.0, function()
        if not inst:IsValid() then return end
        
        if inst.Physics then
            inst.Physics:Teleport(spawn_x, spawn_y, spawn_z)
        else
            inst.Transform:SetPosition(spawn_x, spawn_y, spawn_z)
        end
        
        if inst.SoundEmitter then
            inst.SoundEmitter:PlaySound("dontstarve/common/teleport_generic")
        end
        
        local splash = SpawnPrefab("splash_water")
        if splash then
            splash.Transform:SetPosition(spawn_x, spawn_y, spawn_z)
        end
        
        -- 传送后掉落物品（基本物品栏中随机1/5的物品，排除独特物品和诅咒饰品）
        if inst.components.inventory then
            self:DropRandomItems()
        end
    end)
    
    -- 4. 在2秒后播放wakeup动画并恢复模型碰撞
    inst:DoTaskInTime(2.0, function()
        if not inst:IsValid() then return end
        
        -- wakeup动画开始时显示角色并恢复物理碰撞
        if inst.Show then
            inst:Show()
        end
        
        -- 恢复物理碰撞
        if inst.Physics then
            inst.Physics:SetActive(true)
        end
        
        -- 触发客户端播放wakeup动画（通过RPC）
        --[[ RPC方式（已注释）
        if inst.userid then
            SendModRPCToClient(GetClientModRPC("mod_pono", "drowning_wakeup"), inst.userid)
        end
        --]]
        
        -- 服务器端也播放wakeup动画
        if inst.sg then
            if inst.sg.sg.states.wakeup then
                inst.sg:GoToState("wakeup")
            else
                inst.sg:GoToState("idle")
            end
        end
        
        -- wakeup动画开始后2.3秒恢复操作（共4.3秒）
        inst:DoTaskInTime(2.3, function()
            if inst:IsValid() then
                inst:RemoveTag("busy")
                inst:RemoveTag("pono_drowning_busy")
                inst:RemoveTag("notarget")
                inst:RemoveTag("noattack")
                
                -- 服务器端恢复移动
                if inst.components.locomotor then
                    inst.components.locomotor:RemoveExternalSpeedMultiplier(inst, "drowning_server")
                end
                
                -- 恢复playercontroller
                if inst.components.playercontroller then
                    inst.components.playercontroller:Enable(true)
                end
                
                -- 触发客户端恢复控制事件
                inst:PushEvent("pono_drowning_end")
            end
        end)
    end)
end

-- 掉落随机物品
function mod_pono_drowning:DropRandomItems()
    local inst = self.inst
    local inventory = inst.components.inventory
    
    if not inventory then
        return
    end
    
    -- 获取所有物品栏物品
    local items = {}
    for k = 0, inventory.maxslots - 1 do
        local item = inventory:GetItemInSlot(k + 1)
        if item and self:CanDropItem(item) then
            table.insert(items, item)
        end
    end
    
    -- 计算要掉落的数量（1/5）
    local drop_count = math.max(1, math.floor(#items * self.item_drop_fraction))
    
    -- 随机掉落
    for i = 1, drop_count do
        if #items == 0 then
            break
        end
        
        local index = math.random(1, #items)
        local item = table.remove(items, index)
        
        if item and item:IsValid() then
            inventory:DropItem(item, true, true)
        end
    end
end

-- 检查物品是否可以掉落
---@param item ent
---@return boolean
function mod_pono_drowning:CanDropItem(item)
    if not item or not item:IsValid() then
        return false
    end
    
    -- 不掉落独特物品（unique）
    if item:HasTag("irreplaceable") or item:HasTag("_named") then
        return false
    end
    
    -- 不掉落诅咒饰品（cursed trinkets）
    if item:HasTag("cursed") or item:HasTag("trinket") then
        return false
    end
    
    -- 不掉落装备槽物品
    if item.components.equippable then
        return false
    end
    
    return true
end

function mod_pono_drowning:OnSave()
    return {
        health_penalty = self.health_penalty,
        hunger_penalty = self.hunger_penalty,
        sanity_penalty = self.sanity_penalty,
        min_value = self.min_value,
        moisture_gain = self.moisture_gain,
        item_drop_fraction = self.item_drop_fraction,
    }
end

function mod_pono_drowning:OnLoad(data)
    if data then
        self.health_penalty = data.health_penalty or self.health_penalty
        self.hunger_penalty = data.hunger_penalty or self.hunger_penalty
        self.sanity_penalty = data.sanity_penalty or self.sanity_penalty
        self.min_value = data.min_value or self.min_value
        self.moisture_gain = data.moisture_gain or self.moisture_gain
        self.item_drop_fraction = data.item_drop_fraction or self.item_drop_fraction
    end
end

return mod_pono_drowning